package org.msb.accentis.gui.transactions;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.msb.accentis.data.pojo.Account;
import org.msb.accentis.data.pojo.Category;
import org.msb.accentis.data.pojo.Individual;
import org.msb.accentis.data.pojo.Payee;
import org.msb.accentis.data.pojo.Transaction;
import org.msb.accentis.data.pojo.TransactionDetail;

public class ComplexTransactionAdapter extends AbstractTransactionAdapter {

	private List<Integer> detailIds = new ArrayList<Integer>();

	private List<Account> accounts = new ArrayList<Account>();

	private List<Payee> payees = new ArrayList<Payee>();

	private List<Category> categories = new ArrayList<Category>();

	private List<Individual> individuals = new ArrayList<Individual>();

	private List<BigDecimal> amounts = new ArrayList<BigDecimal>();

	private List<String> descriptions = new ArrayList<String>();

	private Payee payee;

	private String description;

	public ComplexTransactionAdapter(Transaction transaction, Account account) {
		super(transaction, account);

		payee = transaction.getPayee();
		description = transaction.getDescription();

		List<TransactionDetail> details = transaction.getTransactionDetails();
		for (TransactionDetail detail : details)
			addDetailParts(detail);
	}

	private void addDetailParts(TransactionDetail detail) {
		detailIds.add(detail.getId());
		payees.add(detail.getPayee());
		categories.add(detail.getCategory());
		individuals.add(detail.getIndividual());
		amounts.add(detail.getAmount());
		descriptions.add(detail.getDescription());
	}

	public int getDetailCount() {
		return detailIds.size();
	}

	@Override
	public BigDecimal getAmount() {
		BigDecimal totalAmount = BigDecimal.ZERO;

		for (BigDecimal amount : amounts)
			totalAmount = totalAmount.add(null == amount ? BigDecimal.ZERO : amount);

		return totalAmount;
	}

	public Payee getPayee() {
		return payee;
	}

	public void setPayee(Payee value) {
		payee = value;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String value) {
		description = value;
	}

	public Object getValueAt(int row, int col) {
		switch (col) {
		case 0:
			return getDetailAccountAt(row);
		case 1:
			return getDetailPayeeAt(row);
		case 2:
			return getDetailParentCategoryAt(row);
		case 3:
			return getDetailSubcategoryAt(row);
		case 4:
			return getDetailIndividualAt(row);
		case 5:
			return getDetailDescriptionAt(row);
		case 6:
			return getDetailAmountAt(row);
		}

		return null;
	}

	public void setValueAt(int row, int col, Object value) {
		switch (col) {
		case 0:
			setDetailAccountAt(row, (Account) value);
			break;
		case 1:
			setDetailPayeeAt(row, (Payee) value);
			break;
		case 2:
			setDetailParentCategoryAt(row, (Category) value);
			break;
		case 3:
			setDetailSubcategoryAt(row, (Category) value);
			break;
		case 4:
			setDetailIndividualAt(row, (Individual) value);
			break;
		case 5:
			setDetailDescriptionAt(row, (String) value);
			break;
		case 6:
			setDetailAmountAt(row, (BigDecimal) value);
			break;
		}
	}

	private Account getDetailAccountAt(int row) {
		return accounts.get(row);
	}

	private void setDetailAccountAt(int row, Account account) {
		accounts.set(row, account);
	}

	private Payee getDetailPayeeAt(int row) {
		return payees.get(row);
	}

	private void setDetailPayeeAt(int row, Payee payee) {
		payees.set(row, payee);
	}

	private Category getDetailCategoryAt(int row) {
		return categories.get(row);
	}

	private Category getDetailParentCategoryAt(int row) {
		Category category = getDetailCategoryAt(row);

		if (null != category && category.isSubCategory())
			return category.getParentCategory();

		return category;
	}

	private Category getDetailSubcategoryAt(int row) {
		Category category = getDetailCategoryAt(row);

		if (null != category && category.isSubCategory())
			return category;

		return null;
	}

	private void setDetailParentCategoryAt(int row, Category category) {
		if (null == category)
			setDetailCategoryAt(row, null);
		else if (!category.equals(getDetailParentCategoryAt(row)))
			setDetailCategoryAt(row, category);
	}
	
	private void setDetailSubcategoryAt(int row, Category category) {
		if (null == category)
			setDetailCategoryAt(row, getDetailParentCategoryAt(row));
		else
			setDetailCategoryAt(row, category);
	}

	private void setDetailCategoryAt(int row, Category category) {
		categories.set(row, category);
	}

	private Individual getDetailIndividualAt(int row) {
		return individuals.get(row);
	}

	private void setDetailIndividualAt(int row, Individual individual) {
		individuals.set(row, individual);
	}

	private String getDetailDescriptionAt(int row) {
		return descriptions.get(row);
	}

	private void setDetailDescriptionAt(int row, String description) {
		descriptions.set(row, description);
	}

	private BigDecimal getDetailAmountAt(int row) {
		return amounts.get(row);
	}

	private void setDetailAmountAt(int row, BigDecimal amount) {
		amounts.set(row, amount);
	}

	public void saveTransaction() {
		super.saveTransaction();

		getActualTransaction().setPayee(getPayee());
		getActualTransaction().setDescription(getDescription());

		List<TransactionDetail> details = getActualTransaction().getTransactionDetails();

		for (Iterator<TransactionDetail> it = details.iterator(); it.hasNext();) {
			TransactionDetail existingDetail = it.next();
			int pos = detailIds.indexOf(existingDetail.getId());

			if (0 > pos)
				it.remove();
			else
				updateDetail(existingDetail, pos);
		}

		for (int i = 0; i < detailIds.size(); ++i)
			if (0 == detailIds.get(i)) {
				TransactionDetail detail = new TransactionDetail();
				updateDetail(detail, i);
				details.add(detail);
			}
	}

	private void updateDetail(TransactionDetail detail, int pos) {
		detail.setAccount(getDetailAccountAt(pos));
		detail.setAmount(getDetailAmountAt(pos));
		detail.setCategory(getDetailCategoryAt(pos));
		detail.setDescription(getDetailDescriptionAt(pos));
		detail.setIndividual(getDetailIndividualAt(pos));
		detail.setPayee(getDetailPayeeAt(pos));
	}

	public void addDetail() {
		detailIds.add(0);
		accounts.add(null);
		amounts.add(null);
		categories.add(null);
		descriptions.add(null);
		individuals.add(null);
		payees.add(null);
	}
	
	public void removeDetail(int row) {
		detailIds.remove(row);
		accounts.remove(row);
		amounts.remove(row);
		categories.remove(row);
		descriptions.remove(row);
		individuals.remove(row);
		payees.remove(row);
	}
}
